package edu.ucsb.cs176b.android;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

public class MyMap extends MapActivity {
	
	private MapView mapView;
	private MapController mapController;
    private MyLocationOverlay mlo;
    private GeoPoint myLocation;
    
    private List<Treasure> treasures;
    private int numberOfTreasures;
    private int currentTreasure;
    private String token = null;
    private String host = null;
    
	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.map);
		
		mapView = (MapView) findViewById(R.id.mapview);
		mapView.setBuiltInZoomControls(true);
		mapController = mapView.getController();
		
		mapController.setZoom(18);
        mapView.setEnabled(true);
        mapView.setSatellite(false);
        
        treasures = new ArrayList<Treasure>();
        
        // Get data from intent
        numberOfTreasures = getIntent().getExtras().getInt("numberOfTreasures");
        currentTreasure = getIntent().getExtras().getInt("currentTreasure");
        token = getIntent().getExtras().getString("token");
        host = getIntent().getExtras().getString("host");
        
        // Put a listener on button to update position
        Button queryButton = (Button)findViewById(R.id.my_position);
        queryButton.setOnClickListener(new OnClickListener() {
        	public void onClick(View v) {
        		goToMyPosition();
        	}
        });
	}
	
	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		// disable to save battery
		mlo.disableMyLocation();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		// enable find my location
		mlo = new MyLocationOverlay(this, mapView); 
		mlo.enableMyLocation(); 
		mlo.enableCompass();
		
		goToMyPosition();
	}
	
	private void goToMyPosition(){
		mlo.runOnFirstFix(new Runnable() {
            public void run() {
            	myLocation = mlo.getMyLocation();
            	mapView.getOverlays().clear();
            	mapView.getOverlays().add(new MyOverlay());
                mapController.animateTo(mlo.getMyLocation());
                showTreasures();
            }
        });
	}
	
	private void showTreasures(){

		if( myLocation != null ){
			// Tell the user something actually happened
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(getApplicationContext(), "Updating...", Toast.LENGTH_SHORT).show();	
				}
			}); 
					
			double myLat = (myLocation.getLatitudeE6() / 100000.0);
			double myLong = (myLocation.getLongitudeE6() / 100000.0);
						
			for (int i = 1; i < numberOfTreasures + 1; i++) {
				try {
					String strResponse = NetworkUtil.getSringFromUrl("http://"+ host +"/query?token=" + token + "&latitude=" + myLat + "&longitude=" + myLong + "&cid=" + i );
					
					Log.d("MyMap", "Response on query to #" + i + ": " + strResponse);
					
					JSONObject json = new JSONObject(strResponse);
					JSONObject status = json.getJSONObject("status");
							
					// If success
					if(status.getInt("code")==0){
						JSONObject jsonResponse = json.getJSONObject("response");
								
						double distance = jsonResponse.getDouble("distance");
						double angle = jsonResponse.getDouble("angle");
							
						// Calculate treasure latitude and longitude (from slides)
						double tLat = myLat + (distance * Math.cos(angle));
						double tLong = myLong + (distance * Math.sin(angle));
						
						Log.d("MyMap", "Location #" + i + ": " + tLong + ", " + tLat);
						//
						treasures.add( new Treasure( i , new GeoPoint( (int)(tLat * 1E6), (int)(tLong * 1E6) ) ) );
					}
							
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
						
			// Points added for testing
			//treasures.add( new Treasure(2, new GeoPoint( (int)(38 * 1E6), (int)(-100 * 1E6) ) ) );
						
						
			// Add treasure overlay to map
			mapView.getOverlays().add(new TreasureOverlay());
						
						
			// find the lat, lon span
			int minLatitude = myLocation.getLatitudeE6();
			int maxLatitude = myLocation.getLatitudeE6();
			int minLongitude = myLocation.getLongitudeE6();
			int maxLongitude = myLocation.getLongitudeE6();
			
			// Find the boundaries of the item set
			for (Treasure t : treasures) {
				int lat = t.getLocation().getLatitudeE6(); 
				int lon = t.getLocation().getLongitudeE6();
			
				maxLatitude = Math.max(lat, maxLatitude);
				minLatitude = Math.min(lat, minLatitude);
				maxLongitude = Math.max(lon, maxLongitude);
				minLongitude = Math.min(lon, minLongitude);
			}
			
			// leave some padding from corners
			// such as 0.1 for hpadding and 0.2 for vpadding
			maxLatitude = maxLatitude + (int)((maxLatitude-minLatitude)*0.1);
			minLatitude = minLatitude - (int)((maxLatitude-minLatitude)*0.1);
			
			maxLongitude = maxLongitude + (int)((maxLongitude-minLongitude)*0.2);
			minLongitude = minLongitude - (int)((maxLongitude-minLongitude)*0.2);
			
			// Calculate the lat, lon spans from the given pois and zoom
			mapController.zoomToSpan(Math.abs(maxLatitude - minLatitude), Math.abs(maxLongitude - minLongitude));
			
			// Animate to the center of the cluster of points
			mapController.animateTo(new GeoPoint( (maxLatitude + minLatitude) / 2, (maxLongitude + minLongitude) / 2) );
				        
		}
		else {
			// We must wait for the userLocation to be set
			runOnUiThread(new Runnable() {
				public void run() {
					Toast.makeText(getApplicationContext(), "Please wait till the phone finds your location. Try again!", Toast.LENGTH_LONG).show();	
				}
			});
		}
	}
	
	class MyOverlay extends Overlay {
		@Override

		public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
			super.draw(canvas, mapView, shadow);
			Paint paint = new Paint();
			// Converts lat/lng-Point to OUR coordinates on the screen.
			Point myScreenCoords = new Point();
			mapView.getProjection().toPixels(myLocation, myScreenCoords);
			paint.setStrokeWidth(1);
			paint.setARGB(255, 255, 0, 0);
			paint.setStyle(Paint.Style.STROKE);
			
			Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.im_here_b);
			canvas.drawBitmap(bmp, myScreenCoords.x-10, myScreenCoords.y-10, paint);
			canvas.drawText("Here I am...", myScreenCoords.x-25, myScreenCoords.y-15, paint);
			
			return true;
		}

	}
	
	class TreasureOverlay extends Overlay {
		@Override

		public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
			super.draw(canvas, mapView, shadow);
			for(Treasure t : treasures){
				Paint paint = new Paint();
				// Converts lat/lng-Point to OUR coordinates on the screen.
				Point myScreenCoords = new Point();
				mapView.getProjection().toPixels(t.getLocation(), myScreenCoords);
				paint.setStrokeWidth(1);
				paint.setARGB(255, 255, 0, 0);
				paint.setStyle(Paint.Style.STROKE);
				
				Bitmap bmp;
				if(t.getId()==currentTreasure)
					bmp = BitmapFactory.decodeResource(getResources(), R.drawable.treasure_chest);
				else
					bmp = BitmapFactory.decodeResource(getResources(), R.drawable.treasure_chest);
				
				canvas.drawBitmap(bmp, myScreenCoords.x-10, myScreenCoords.y-10, paint);
				canvas.drawText("Treasure #" + t.getId(), myScreenCoords.x-35, myScreenCoords.y-15, paint);
			}	
			
			return true;
		}
	}
	
	// Just a class to wrap Treasure ID and location
	class Treasure {
		
		private int id;
		private GeoPoint point;
		
		public Treasure(int id, GeoPoint p) {
			this.id = id;
			this.point = p;
		}
		
		public int getId(){
			return id;
		}
		
		public GeoPoint getLocation(){
			return point;
		}	
		
	}

}
